﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;

namespace GBricks.Collections
{
  [Serializable]
  public class ReadOnlySortedSet<T> : ReadOnlySet<T>
  {
    private static readonly ReadOnlySortedSet<T> EmptyInstance = new ReadOnlySortedSet<T>(new SortedSet<T>());

    public ReadOnlySortedSet(SortedSet<T> items)
      : base(items) {
      Argument.NotNull(items, "items");
    }

    public static ReadOnlySortedSet<T> Empty {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<ReadOnlySortedSet<T>>() != null);
        return EmptyInstance;
      }
    }

    protected new SortedSet<T> Items {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<SortedSet<T>>() != null);
        return (SortedSet<T>)base.Items;
      }
    }

    public IComparer<T> Comparer {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<IComparer<T>>() != null);
        return Items.Comparer; 
      }
    }

    public T Max {
      [DebuggerStepThrough]
      get { return Items.Max; }
    }

    public T Min {
      [DebuggerStepThrough]
      get { return Items.Min; }
    }

    [ContractInvariantMethod]
    private void Invariant() {
      Contract.Invariant(Items != null);
      Contract.Invariant(Items.Comparer != null);
    }

    [Pure]
    [SuppressMessage("Microsoft.Contracts", "Ensures", Justification = Justifications.WrappedTypeDoesNotHaveEnsures)]
    public SortedSet<T> GetViewBetween(T lowerValue, T upperValue) {
      Argument.OutOfRange(Comparer.Compare(lowerValue, upperValue) <= 0, "lowerValue");
      Contract.Ensures(Contract.Result<SortedSet<T>>() != null);
      return Items.GetViewBetween(lowerValue, upperValue);
    }

    [Pure]
    [SuppressMessage("Microsoft.Contracts", "Ensures", Justification = Justifications.WrappedTypeDoesNotHaveEnsures)]
    public IEnumerable<T> Reverse() {
      Contract.Ensures(Contract.Result<IEnumerable<T>>() != null);
      return Items.Reverse();
    }

    [Pure]
    public void CopyTo(T[] array) {
      Argument.NotNull(array, "array");
      Items.CopyTo(array);
    }

    [Pure]
    public void CopyTo(T[] array, int arrayIndex, int count) {
      Argument.NotNull(array, "array");
      Argument.OutOfRange(arrayIndex >= 0, "arrayIndex");
      Argument.OutOfRange(count >= 0, "count");
      Argument.OutOfRange(arrayIndex <= array.Length - count, "arrayIndex");

      Items.CopyTo(array, arrayIndex, count);
    }

    [Pure]
    public new SortedSet<T>.Enumerator GetEnumerator() {
      return Items.GetEnumerator();
    }
  }
}
